#include "pwm.h"

#include "stm32f10x.h" // Device header

/**
 * @brief  初始化PWM所需时基单元、输出端口、所需比较器及输出通道
 * 
 * @param  PWMx 先定义新结构体PWM_Builder，其中TIMx可选择：TIM2、TIM3、TIM4
 * @retval 0 正常；-1 错误
 */
int PWM_Init(PWM_Builder *PWMx) {

	GPIO_InitTypeDef PWM_GIPOInitStructure;
	PWM_GIPOInitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	PWM_GIPOInitStructure.GPIO_Speed = GPIO_Speed_50MHz;

	// Init RCC and GPIO
	if (PWMx->PWM_TIMx == TIM2)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

		switch (PWMx->OCx)
		{
			case OC1: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_0; break;
			case OC2: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_1; break;
			case OC3: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_2; break;
			case OC4: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_3; break;
		}
		GPIO_Init(GPIOA, &PWM_GIPOInitStructure);
	}
	else if (PWMx->PWM_TIMx == TIM3)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

		switch (PWMx->OCx)
		{
		case OC1:
			PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_6;
			GPIO_Init(GPIOA, &PWM_GIPOInitStructure);
			break;
		case OC2:
			PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_7;
			GPIO_Init(GPIOA, &PWM_GIPOInitStructure);
			break;
		case OC3:
			PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_0;
			GPIO_Init(GPIOB, &PWM_GIPOInitStructure);
			break;
		case OC4:
			PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_1;
			GPIO_Init(GPIOB, &PWM_GIPOInitStructure);
			break;
		}
	}
	else if (PWMx->PWM_TIMx == TIM4)
	{
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

		switch (PWMx->OCx)
		{
			case OC1: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_6; break;
			case OC2: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_7; break;
			case OC3: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_8; break;
			case OC4: PWM_GIPOInitStructure.GPIO_Pin = GPIO_Pin_9; break;
		}
		GPIO_Init(GPIOB, &PWM_GIPOInitStructure);
	}
	else
	{
		return -1; //函数执行错误返回
	}

	TIM_InternalClockConfig(PWMx->PWM_TIMx);  // 内部时钟

	TIM_TimeBaseInitTypeDef PWM_TimeBaseInitStructure;
	PWM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	PWM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
	PWM_TimeBaseInitStructure.TIM_Period = PWMx->Reso - 1;
	PWM_TimeBaseInitStructure.TIM_Prescaler = 72000000 / (PWMx->Freq * PWMx->Reso) - 1; //预分配器与计数器有偏差，-1补偿
	PWM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;                    //高级定时器参数，不使用
	TIM_TimeBaseInit(PWMx->PWM_TIMx, &PWM_TimeBaseInitStructure);
	// TIM_ClearFlag(TIMX,TIM_FLAG_Update);      //清除初次中断更新标志位

	// 比较器初始化
	TIM_OCInitTypeDef PWM_TimOCInitStructure;
	TIM_OCStructInit(&PWM_TimOCInitStructure); //赋初始值
	PWM_TimOCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	PWM_TimOCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	PWM_TimOCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	PWM_TimOCInitStructure.TIM_Pulse = 0; //初始化占空比0
	
	switch (PWMx->OCx)
	{
		case OC1: TIM_OC1Init(PWMx->PWM_TIMx, &PWM_TimOCInitStructure); break;
		case OC2: TIM_OC2Init(PWMx->PWM_TIMx, &PWM_TimOCInitStructure); break;
		case OC3: TIM_OC3Init(PWMx->PWM_TIMx, &PWM_TimOCInitStructure); break;
		case OC4: TIM_OC4Init(PWMx->PWM_TIMx, &PWM_TimOCInitStructure); break;
	}

	TIM_Cmd(PWMx->PWM_TIMx, ENABLE);

	return 0;
}

/**
 * @brief  设置PWM占空比到OC1
 * 
 * @param  PWMx 
 * @param  Duty 占空比，范围：0 ~ 1，精度 = 1/Reso
 */
void PWM_OC1SetDuty(PWM_Builder *PWMx, float Duty) {

	PWMx->Duty = Duty;

	TIM_SetCompare1(PWMx->PWM_TIMx, (uint16_t)(PWMx->Duty * PWMx->Reso));
}

/**
 * @brief  设置PWM占空比到OC2
 * 
 * @param  PWMx 
 * @param  Duty 占空比，范围：0 ~ 1，精度 = 1/Reso
 */
void PWM_OC2SetDuty(PWM_Builder *PWMx, float Duty) {

	PWMx->Duty = Duty;

	TIM_SetCompare2(PWMx->PWM_TIMx, (uint16_t)(PWMx->Duty * PWMx->Reso));
}

/**
 * @brief  设置PWM占空比到OC3
 * 
 * @param  PWMx 
 * @param  Duty 占空比，范围：0 ~ 1，精度 = 1/Reso
 */
void PWM_OC3SetDuty(PWM_Builder *PWMx, float Duty) {

	PWMx->Duty = Duty;

	TIM_SetCompare3(PWMx->PWM_TIMx, (uint16_t)(PWMx->Duty * PWMx->Reso));
}

/**
 * @brief  设置PWM占空比到OC4
 * 
 * @param  PWMx 
 * @param  Duty 占空比，范围：0 ~ 1，精度 = 1/Reso
 */
void PWM_OC4SetDuty(PWM_Builder *PWMx, float Duty) {

	PWMx->Duty = Duty;

	TIM_SetCompare4(PWMx->PWM_TIMx, (uint16_t)(PWMx->Duty * PWMx->Reso));
}
